package com.wzh.common.mybatis.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wzh.common.general.exception.CustomerException;
import com.wzh.common.general.result.PageQuery;
import com.wzh.common.general.result.PageResult;

import java.lang.reflect.InvocationTargetException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * MyBatis分页工具类
 *
 * @author wzh
 */
public class MybatisPageUtils {

    /**
     * 将MyBatis-Plus的Page对象转换为PageResult
     *
     * @param page MyBatis-Plus分页对象
     * @param <T>  数据类型
     * @return PageResult对象
     */
    public static <T> PageResult<T> toPageResult(Page<T> page) {
        return toPageResult(page, Function.identity());
    }

    /**
     * 将MyBatis-Plus的Page对象转换为PageResult，并指定数据转换函数
     *
     * @param page      MyBatis-Plus分页对象
     * @param converter 数据转换函数
     * @param <T>       源数据类型
     * @param <R>       目标数据类型
     * @return PageResult对象
     */
    public static <T, R> PageResult<R> toPageResult(Page<T> page, Function<T, R> converter) {
        List<R> convertedList = page.getRecords().stream()
                .map(converter)
                .toList();

        return PageResult.of(
                Math.toIntExact(page.getCurrent()),
                Math.toIntExact(page.getSize()),
                Math.toIntExact(page.getTotal()),
                convertedList
        );
    }

    /**
     * 将MyBatis-Plus的Page对象转换为PageResult，并自动映射到DTO
     *
     * @param page     MyBatis-Plus分页对象
     * @param dtoClass DTO类
     * @param <T>      源数据类型
     * @param <R>      目标数据类型
     * @return PageResult对象
     */
    public static <T, R> PageResult<R> toPageResult(Page<T> page, Class<R> dtoClass) {
        Objects.requireNonNull(dtoClass, "目标DTO类不能为空");
        return toPageResult(page, data -> convert(data, dtoClass));
    }

    /**
     * 将MyBatis-Plus的Page对象转换为PageResult，并在转换后执行自定义逻辑
     *
     * @param page       MyBatis-Plus分页对象
     * @param dtoClass   DTO类
     * @param customizer 自定义处理逻辑（Consumer）
     * @param <T>        源数据类型
     * @param <R>        目标数据类型
     * @return PageResult对象
     */
    public static <T, R> PageResult<R> toPageResult(Page<T> page, Class<R> dtoClass, Consumer<R> customizer) {
        Objects.requireNonNull(dtoClass, "目标DTO类不能为空");
        Objects.requireNonNull(customizer, "自定义处理器不能为空");

        List<R> convertedList = page.getRecords().stream()
                .map(data -> {
                    R dto = convert(data, dtoClass);
                    customizer.accept(dto);
                    return dto;
                })
                .toList();

        return PageResult.of(
                Math.toIntExact(page.getCurrent()),
                Math.toIntExact(page.getSize()),
                Math.toIntExact(page.getTotal()),
                convertedList
        );
    }

    /**
     * 创建空的分页结果
     *
     * @param pageNum  页码
     * @param pageSize 页大小
     * @param <T>      数据类型
     * @return 空的PageResult对象
     */
    public static <T> PageResult<T> empty(int pageNum, int pageSize) {
        return PageResult.of(pageNum, pageSize, 0, List.of());
    }

    /**
     * 将源对象转换为DTO
     *
     * @param t   源对象
     * @param <T> 源对象类型
     * @param <R> DTO类型
     * @return DTO对象
     * @throws CustomerException 源对象为null或实例化失败时抛出
     */
    public static <T, R> R convert(T t, Class<R> dtoClass) {
        if (t == null) {
            throw new IllegalArgumentException("源对象 t 不能为 null");
        }

        try {
            R dto = dtoClass.getDeclaredConstructor().newInstance();
            BeanUtil.copyProperties(t, dto);
            return dto;
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
                 NoSuchMethodException e) {
            throw new CustomerException("DTO 实例化失败: " + dtoClass.getName());
        }
    }

    /**
     * 将源对象列表转换为DTO列表
     *
     * @param tList    源对象列表
     * @param <T>      源对象类型
     * @param dtoClass
     * @return DTO列表
     */
    public static <T, R> List<R> convertList(List<T> tList, Class<R> dtoClass) {
        return tList.stream()
                .map(t -> convert(t, dtoClass))
                .toList();
    }

    /**
     * 创建MyBatis-Plus分页对象
     *
     * @param pageQuery 分页查询参数
     * @param <T>       查询条件类型
     * @return Page对象
     */
    public static <T> Page<T> createPage(PageQuery<?> pageQuery) {
        return new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
    }

    /**
     * 处理排序条件（支持多字段排序）
     *
     * @param queryWrapper  查询包装器
     * @param pageQuery     分页查询参数
     * @param defaultFields 默认排序字段
     * @param <T>           实体类型
     */
    public static <T> void handleOrderBy(QueryWrapper<T> queryWrapper, PageQuery<?> pageQuery, String... defaultFields) {
        if (CharSequenceUtil.isNotBlank(pageQuery.getOrderBy())) {
            String[] orderFields = pageQuery.getOrderBy().split(",");
            boolean isAsc = !"desc".equalsIgnoreCase(pageQuery.getOrderMode());

            for (String field : orderFields) {
                if (CharSequenceUtil.isNotBlank(field.trim())) {
                    queryWrapper.orderBy(true, isAsc, field.trim());
                }
            }
        } else if (defaultFields != null) {
            // 使用指定的默认排序字段
            for (String field : defaultFields) {
                if (CharSequenceUtil.isNotBlank(field)) {
                    queryWrapper.orderBy(true, true, field);
                }
            }
        }
    }

    /**
     * 处理排序条件（支持多字段排序）
     *
     * @param pageQuery     分页查询参数
     * @param defaultFields 默认排序字段
     * @param <T>           实体类型
     */
    public static <T> QueryWrapper<T> handleOrderBy(PageQuery<?> pageQuery, String... defaultFields) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        handleOrderBy(queryWrapper, pageQuery, defaultFields);
        return queryWrapper;
    }


    /**
     * 处理排序条件和高级查询（支持多字段排序）
     *
     * @param pageQuery     分页查询参数
     * @param defaultFields 默认排序字段
     * @param <T>           实体类型
     */
    public static <T> QueryWrapper<T> handleOrderByAndQuery(PageQuery<?> pageQuery, String... defaultFields) {
        QueryWrapper<T> queryWrapper = handleOrderBy(pageQuery, defaultFields);
        // 处理高级查询条件
        if (pageQuery.getAdvancedQuery() != null && pageQuery.getAdvancedQuery().getConditions() != null) {
            MybatisPageUtils.handleAdvancedQuery(queryWrapper, pageQuery.getAdvancedQuery().getConditions());
        }
        return queryWrapper;
    }

    public static <T> LambdaQueryWrapper<T> handleOrderByAndQueryLambda(PageQuery<?> pageQuery, String... defaultFields) {
        QueryWrapper<T> objectQueryWrapper = handleOrderByAndQuery(pageQuery,defaultFields);
        return objectQueryWrapper.lambda();
    }

    /**
     * 处理高级查询条件
     *
     * @param queryWrapper 查询包装器
     * @param conditions   查询条件列表
     * @param <T>          实体类型
     */
    public static <T> void handleAdvancedQuery(QueryWrapper<T> queryWrapper, List<Map<String, Object>> conditions) {
        if (conditions == null || conditions.isEmpty()) {
            return;
        }

        for (Map<String, Object> condition : conditions) {
            String field = MapUtil.getStr(condition,"field");
            String operator = MapUtil.getStr(condition,"operator");
            Object value = condition.get("value");

            if (CharSequenceUtil.isBlank(field) || CharSequenceUtil.isBlank(operator)) {
                continue;
            }

            // 将驼峰命名转换为下划线命名
            String columnName = camelToUnderscore(field);

            switch (operator) {
                case "eq":
                    queryWrapper.eq(value != null, columnName, value);
                    break;
                case "ne":
                    queryWrapper.ne(value != null, columnName, value);
                    break;
                case "like":
                    queryWrapper.like(CharSequenceUtil.isNotBlank((String) value), columnName, value);
                    break;
                case "notLike":
                    queryWrapper.notLike(CharSequenceUtil.isNotBlank((String) value), columnName, value);
                    break;
                case "likeLeft":
                    queryWrapper.likeLeft(CharSequenceUtil.isNotBlank((String) value), columnName, value);
                    break;
                case "likeRight":
                    queryWrapper.likeRight(CharSequenceUtil.isNotBlank((String) value), columnName, value);
                    break;
                case "gt":
                    queryWrapper.gt(value != null, columnName, parseValue(value));
                    break;
                case "ge":
                    queryWrapper.ge(value != null, columnName, parseValue(value));
                    break;
                case "lt":
                    queryWrapper.lt(value != null, columnName, parseValue(value));
                    break;
                case "le":
                    queryWrapper.le(value != null, columnName, parseValue(value));
                    break;
                case "in":
                    if (value instanceof String) {
                        List<String> values = Arrays.asList(((String) value).split(","));
                        queryWrapper.in(!values.isEmpty(), columnName, values);
                    } else if (value instanceof List) {
                        queryWrapper.in(!((List<?>) value).isEmpty(), columnName, (List<?>) value);
                    }
                    break;
                case "notIn":
                    if (value instanceof String) {
                        List<String> values = Arrays.asList(((String) value).split(","));
                        queryWrapper.notIn(!values.isEmpty(), columnName, values);
                    } else if (value instanceof List) {
                        queryWrapper.notIn(!((List<?>) value).isEmpty(), columnName, (List<?>) value);
                    }
                    break;
                case "isNull":
                    queryWrapper.isNull(columnName);
                    break;
                case "isNotNull":
                    queryWrapper.isNotNull(columnName);
                    break;
                default:
                    // 默认使用等于
                    queryWrapper.eq(value != null, columnName, value);
                    break;
            }
        }
    }

    /**
     * 处理高级查询条件（Lambda版本）
     *
     * @param conditions 查询条件列表
     * @param <T>        实体类型
     * @return LambdaQueryWrapper
     */
    public static <T> LambdaQueryWrapper<T> handleAdvancedQuery(List<Map<String, Object>> conditions) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        handleAdvancedQuery(queryWrapper, conditions);
        return queryWrapper.lambda();
    }

    /**
     * 处理分页查询中的高级查询条件
     *
     * @param queryWrapper 查询包装器
     * @param pageQuery    分页查询参数
     * @param <T>          实体类型
     */
    public static <T> void handlePageAdvancedQuery(QueryWrapper<T> queryWrapper, PageQuery<?> pageQuery) {
        if (pageQuery.getAdvancedQuery() != null && pageQuery.getAdvancedQuery().getConditions() != null) {
            handleAdvancedQuery(queryWrapper, pageQuery.getAdvancedQuery().getConditions());
        }
    }

    /**
     * 处理分页查询中的高级查询条件（Lambda版本）
     *
     * @param pageQuery 分页查询参数
     * @param <T>       实体类型
     * @return LambdaQueryWrapper
     */
    public static <T> LambdaQueryWrapper<T> handlePageAdvancedQuery(PageQuery<?> pageQuery) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        handlePageAdvancedQuery(queryWrapper, pageQuery);
        return queryWrapper.lambda();
    }

    /**
     * 将驼峰命名转换为下划线命名
     *
     * @param camelCase 驼峰命名字符串
     * @return 下划线命名字符串
     */
    private static String camelToUnderscore(String camelCase) {
        if (StrUtil.isBlank(camelCase)) {
            return camelCase;
        }
        return camelCase.replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase();
    }

    /**
     * 解析值，处理日期时间类型
     *
     * @param value 原始值
     * @return 解析后的值
     */
    private static Object parseValue(Object value) {
        if (value == null) {
            return null;
        }

        if (value instanceof String) {
            String strValue = (String) value;
            
            // 尝试解析为日期时间
            if (strValue.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")) {
                return LocalDateTime.parse(strValue, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            }
            
            // 尝试解析为日期
            if (strValue.matches("\\d{4}-\\d{2}-\\d{2}")) {
                return LocalDate.parse(strValue, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            }
        }

        return value;
    }

}
